﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.Data.Linq;
using System.Data.Common;
using System.Transactions;
using System.IO;
using System.Diagnostics;
using System.Reflection;
using Srs.Core.Common;

namespace Srs.Sample.Services
{
    [ErrorBehavior(typeof(ServiceErrorHandler))]
    public class CustomerService : ICustomerService
    {
        //This sample is using Linq to SQL
        public List<Customer> GetCustomers()
        {
            using (SRS_Sample db = GetDataContext())
            {
                //var query = from customer in db.Sample_Customers
                //            select customer;
                //return Customer.Convert(query);

                //using the compiled query
                return Customer.Convert(CustomerListQuery(db));
            }
        }


        //Using compiled queries for the sake of speed!!!
        //TODO: Need to ensure this is a true singleton.
        static Func<SRS_Sample, IQueryable<Sample_Customer>> CustomerListQuery =
            CompiledQuery.Compile((SRS_Sample db) => from customer in db.Sample_Customers select customer);



        //This sample is using LINQ to Entities
        public List<Customer> GetCustomersUsingEntities()
        {
            using (Srs_SampleEntities e = new Srs_SampleEntities())
            {
                var query = from customer in e.Customers
                            select customer;

                return Customer.Convert(query);
            }
        }



        public Customer GetCustomer(int customerID)
        {
            using (SRS_Sample db = GetDataContext())
            {
                //Sample_Customer sc = db.Sample_Customers.Single(c => c.ID == customerID);
                //return new Customer(sc);

                //using the compiled query
                return new Customer(CustomerItemQuery(db, customerID));
            }
        }

        //Using compiled queries for the sake of speed!!!
        //TODO: Need to ensure this is a true singleton.
        static Func<SRS_Sample, int, Sample_Customer> CustomerItemQuery =
            CompiledQuery.Compile((SRS_Sample db, int customerId) => db.Sample_Customers.Single(c => c.ID == customerId));


        // stored proc implementation
        public List<Dealer> GetDealersForCustomer(int customerID)
        {
            using (SRS_Sample db = GetDataContext())
            {
                // execute the stored proc
                //ISingleResult<Sample_GetDealersForCustomerResult> dbDealers = db.Sample_GetDealersForCustomer(customerID, "%");

                //use the compiled query

                ISingleResult<Sample_GetDealersForCustomerResult> dbDealers = DealersForCustQuery(db, customerID);
                // turn the stored proc results into a list of Dealers
                List<Dealer> serviceDealers = new List<Dealer>();
                foreach (Sample_GetDealersForCustomerResult d in dbDealers)
                    serviceDealers.Add(new Dealer(d.ID.Value, d.Name));

                return serviceDealers;
            }
        }

        //Using compiled queries for the sake of speed!!!
        //TODO: Need to ensure this is a true singleton.
        static Func<SRS_Sample, int, ISingleResult<Sample_GetDealersForCustomerResult>> DealersForCustQuery =
            CompiledQuery.Compile((SRS_Sample db, int customerID) => db.Sample_GetDealersForCustomer(customerID, "%"));


        public int SaveCustomer(Customer customer)
        {
            using (SRS_Sample db = GetDataContext())
            {
                Sample_Customer sc = customer.ToDatabaseVersion();

                if (sc.ID == 0)
                    db.Sample_Customers.InsertOnSubmit(sc);
                else
                    db.Sample_Customers.Attach(sc, true);

                db.SubmitChanges();
                return sc.ID;
            }
        }




        public void DeleteCustomer(Customer customer)
        {
            using (SRS_Sample db = GetDataContext())
            {
                Sample_Customer sc = customer.ToDatabaseVersion();
                db.Sample_Customers.Attach(sc);
                db.Sample_Customers.DeleteOnSubmit(sc);
                db.SubmitChanges();
            }
        }

        public void TestTransaction()
        {
            using (SRS_Sample db = GetDataContext())
            using (TransactionScope ts = new TransactionScope())
            {
                //int i = 400;
                //foreach (Sample_Customer c in db.Sample_Customers)
                //{
                //    c.Name = "joe" + i.ToString();
                //    db.SubmitChanges();

                //    i++;
                //    if (i == 423)
                //        throw new ApplicationException("kaboom!");
                //}

                int customerID = 7;

                var query2 = from d in db.Sample_Dealers
                             where d.CustomerID == customerID
                             select d;

                db.Sample_Dealers.DeleteAllOnSubmit(query2);
                db.SubmitChanges();

                var query = from c in db.Sample_Customers
                            where c.ID == customerID
                            select c;

                db.Sample_Customers.DeleteAllOnSubmit(query);
                db.SubmitChanges();

                ts.Complete();
            }
        }

        private SRS_Sample GetDataContext()
        {
            string connectionString = "server=(local);database=Srs_Sample;trusted_connection=true;"; // eventually config seting

            SRS_Sample db = new SRS_Sample(connectionString);

            bool logSql = true;   // eventually config seting

            if (logSql)
            {
                StreamWriter sw = File.AppendText(@"c:\temp\linq2sql.log");
                sw.AutoFlush = true;

                StackTrace stackTrace = new StackTrace();
                StackFrame stackFrame = stackTrace.GetFrame(1);
                string callingMethodName = stackFrame.GetMethod().Name;

                sw.WriteLine("");
                sw.WriteLine("---->");
                sw.WriteLine(string.Format("----> DataContext Log Entry for method '{0}' created at {1}", callingMethodName, DateTime.Now));
                sw.WriteLine("---->");

                db.Log = sw;
            }

            return db;
        }
    }
}
